/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = sip_sdp.c                                          */
/*  NOTE      =                                                    */
/*  DATE      = 2015/09/01 by songbb                               */
/*******************************************************************/

#include "conntrack.h"

#include "sip_core.h"
#include "sip_comm.h"
#include "sip_sdp.h"

/*******************************************************************************
*  FUNC     :  解析Connection Data
*  ARGS     :  *p_field                                 (field数据)
*           :  ui_field_len                             (field数据长度)
*           :  **pp_ui_ip                               (解析后的IP)
*           :  *p_i_ip_len                              (解析后的IP个数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __sdp_field_c(char *p_field
                            , unsigned int ui_field_len
                            , unsigned int **pp_ui_ip
                            , int *p_i_ip_len)
{
    char *p_addr = NULL;
    char *p_space1_pos = NULL;
    char *p_space2_pos = NULL;
    char *p_addr_pos = NULL;
    unsigned int ui_addr_len = 0;
    char *p_slash1_pos = NULL;
    char *p_slash2_pos = NULL;
    char *p_num_of_addr = NULL;
    unsigned int ui_num_of_addr_len = 0;
    char *p_num_of_addr_pos = NULL;
    unsigned int ui_addr = 0;
    int i_num_of_addr = 0;
    int i_loop;

    /**
     * c=<network type> <address type> <connection address>
     * c=<network type> <address type> <base multicast address>/<ttl>
     * c=<network type> <address type> <base multicast address>/<ttl>/<number of addresses>
     */

    if((p_space1_pos = (char *) memchr(p_field, ' ', ui_field_len)) == NULL)
        goto error;
    if((p_space2_pos = (char *) memchr(p_space1_pos + 1, ' ', ui_field_len - (p_space1_pos + 1 - p_field))) == NULL)
        goto error;
    p_addr_pos = p_space2_pos + 1;
    ui_addr_len = ui_field_len - (p_addr_pos - p_field);

    if((p_slash1_pos = (char *) memchr(p_addr_pos, '/', ui_addr_len)) != NULL)
    {
        ui_addr_len = p_slash1_pos - p_addr_pos;

        if ((p_addr = (char *) frmalloc(sizeof(char) * (ui_addr_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_addr, p_addr_pos, ui_addr_len);
        p_addr[ui_addr_len] = '\0';
        ui_addr = iptools_parse_ipaddr(p_addr);
        SIP_PRINT_FATAL("p_addr:[%s][%u]\n", p_addr, ui_addr);

        if((p_slash2_pos = (char *) memchr(p_slash1_pos + 1, '/', ui_field_len - (p_slash1_pos + 1 - p_field))) != NULL)
        {
            p_num_of_addr_pos = p_slash2_pos + 1;
            ui_num_of_addr_len = ui_field_len - (p_num_of_addr_pos - p_field);
            if ((p_num_of_addr = (char *) frmalloc(sizeof(char) * (ui_num_of_addr_len + 1))) == NULL)
            {
                SIP_MALLOCK_ERR;
                goto error;
            }
            memcpy(p_num_of_addr, p_num_of_addr_pos, ui_num_of_addr_len);
            p_num_of_addr[ui_num_of_addr_len] = '\0';
            i_num_of_addr = atoi(p_num_of_addr);
            if (i_num_of_addr <= 0)
                goto error;
            *p_i_ip_len = i_num_of_addr;
            if ((*pp_ui_ip = (unsigned int *) frmalloc(sizeof(unsigned int) * i_num_of_addr)) == NULL)
            {
                SIP_MALLOCK_ERR;
                goto error;
            }
            for (i_loop = 0; i_loop < i_num_of_addr; i_loop++)
            {
                *pp_ui_ip[i_loop] = ui_addr + i_loop;
                SIP_PRINT_FATAL("p_addr:[%u]\n", *pp_ui_ip[i_loop]);
            }
        }
        else
        {
            *p_i_ip_len = 1;
            if ((*pp_ui_ip = (unsigned int *) frmalloc(sizeof(unsigned int) * 1)) == NULL)
            {
                SIP_MALLOCK_ERR;
                goto error;
            }
            *pp_ui_ip[0] = ui_addr;
        }
    }
    else
    {
        if ((p_addr = (char *) frmalloc(sizeof(char) * (ui_addr_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_addr, p_addr_pos, ui_addr_len);
        p_addr[ui_addr_len] = '\0';
        ui_addr = iptools_parse_ipaddr(p_addr);
        SIP_PRINT_FATAL("p_addr:[%s][%u]\n", p_addr, ui_addr);

        *p_i_ip_len = 1;
        if ((*pp_ui_ip = (unsigned int *) frmalloc(sizeof(unsigned int) * 1)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        *pp_ui_ip[0] = ui_addr;
    }

    sip_free((void **) &p_addr);
    sip_free((void **) &p_num_of_addr);
    return FR_SUCC;
error:
    sip_free((void **) &p_addr);
    sip_free((void **) &p_num_of_addr);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析Media Announcements
*  ARGS     :  *p_field                                 (field数据)
*           :  ui_field_len                             (field数据长度)
*           :  **pp_i_port                              (解析后的端口)
*           :  *p_i_port_len                            (解析后的端口个数)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __sdp_field_m(char *p_field
                            , unsigned int ui_field_len
                            , int **pp_i_port
                            , int *p_i_port_len
                            , unsigned short *p_us_proto)
{
    int i_port;
    int i_num_of_ports;
    char *p_space1_pos = NULL;
    char *p_space2_pos = NULL;
    char *p_port_pos = NULL;
    char *p_slash_pos = NULL;
    char *p_port = NULL;
    unsigned int ui_port_len;
    char *p_num_of_ports_pos = NULL;
    char *p_num_of_ports = NULL;
    unsigned int ui_num_of_ports_len;
    int i_loop;

    /**
     * m=<media> <port> <transport> <fmt list>
     * m=<media> <port>/<number of ports> <transport> <fmt list>
     */
    if((p_space1_pos = (char *) memchr(p_field, ' ', ui_field_len)) == NULL)
        goto error;
    p_port_pos = p_space1_pos + 1;
    if((p_space2_pos = (char *) memchr(p_port_pos, ' ', ui_field_len - (p_port_pos - p_field))) == NULL)
        goto error;
    ui_port_len = p_space2_pos - p_port_pos;

    /**
     * 检查transport是否是 RTP/AVP or TCP/RTP/AVP
     * XXX: 有些地方会用非标准的tcp进行传输,这里做了适当的适配
     */
    if (memcmp(p_space2_pos + 1, "RTP/AVP", strlen("RTP/AVP")) == 0)
        *p_us_proto = IPPROTO_UDP;
    else if (memcmp(p_space2_pos + 1, "TCP/RTP/AVP", strlen("TCP/RTP/AVP")) == 0 || memcmp(p_space2_pos + 1, "tcp", strlen("tcp")) == 0)
        *p_us_proto = IPPROTO_TCP;
    else
        goto error;

    if((p_slash_pos = (char *) memchr(p_port_pos, '/', ui_port_len)) != NULL)
    {
        ui_port_len = p_slash_pos - p_port_pos;
        if ((p_port = (char *) frmalloc(sizeof(char) * (ui_port_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_port, p_port_pos, ui_port_len);
        p_port[ui_port_len] = '\0';
        i_port = atoi(p_port);

        p_num_of_ports_pos = p_slash_pos + 1;
        ui_num_of_ports_len = p_space2_pos - p_num_of_ports_pos;
        if ((p_num_of_ports = (char *) frmalloc(sizeof(char) * (ui_num_of_ports_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_num_of_ports, p_num_of_ports_pos, ui_num_of_ports_len);
        p_num_of_ports[ui_num_of_ports_len] = '\0';

        i_num_of_ports = atoi(p_num_of_ports);
        if (i_num_of_ports <= 0)
            goto error;
        *p_i_port_len = i_num_of_ports;
        if ((*pp_i_port = (int *) frmalloc(sizeof(int) * i_num_of_ports)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        for (i_loop = 0; i_loop < i_num_of_ports; i_loop++)
        {
            i_port += i_loop * 2;
            *pp_i_port[i_loop] = i_port;
            SIP_PRINT_FATAL("i_port:[%u]\n", i_port);
        }
    }
    else
    {
        ui_port_len = p_space2_pos - p_port_pos;
        if ((p_port = (char *) frmalloc(sizeof(char) * (ui_port_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_port, p_port_pos, ui_port_len);
        p_port[ui_port_len] = '\0';
        i_port = atoi(p_port);

        *p_i_port_len = 1;
        if ((*pp_i_port = (int *) frmalloc(sizeof(int) * 1)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        *pp_i_port[0] = i_port;
        SIP_PRINT_FATAL("i_port:[%u]\n", i_port);
    }

    sip_free((void **) &p_port);
    sip_free((void **) &p_num_of_ports);
    return FR_SUCC;
error:
    sip_free((void **) &p_port);
    sip_free((void **) &p_num_of_ports);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析SDP协议
*  ARGS     :  *p_st_sip_stmt                           (对应的stmt)
*           :  *p_payload                               (Content数据)
*           :  i_payload_len                            (Content数据长度)
*           :  i_is_req                                 (是否是请求包)
*           :
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int sip_dissect_sdp(L7_sip_stmt *p_st_sip_stmt
                    , char *p_payload
                    , int i_payload_len
                    , int i_is_req)
{
    char *p_line_end_pos = NULL;
    unsigned int ui_offset = 0;
    unsigned int ui_line_len = 0;
    char *p_equal_pos = NULL;
    char *p_field_name = NULL;
    unsigned int ui_field_name_len = 0;
    char *p_field_value = NULL;
    unsigned int ui_field_value_len = 0;

    while ((p_line_end_pos = frmemstr(p_payload + ui_offset, i_payload_len - ui_offset, (char *) APM_SIP_EOL, strlen(APM_SIP_EOL))) != NULL)
    {
        if ((ui_line_len = p_line_end_pos - (p_payload + ui_offset)) == 0)
            break;

        if((p_equal_pos = (char *) memchr(p_payload + ui_offset, '=', ui_line_len)) == NULL)
            goto error;
        ui_field_name_len = p_equal_pos - (p_payload + ui_offset);
        if ((p_field_name = (char *) frmalloc(sizeof(char) * (ui_field_name_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_field_name, p_payload + ui_offset, ui_field_name_len);
        p_field_name[ui_field_name_len] = '\0';
        frtrim(p_field_name);

        ui_field_value_len = p_line_end_pos - (p_equal_pos + 1);
        if ((p_field_value = (char *) frmalloc(sizeof(char) * (ui_field_value_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        memcpy(p_field_value, p_equal_pos + 1, ui_field_value_len);
        p_field_value[ui_field_value_len] = '\0';
        frtrim(p_field_value);

        SIP_PRINT_WARN("%s=%s\n", p_field_name, p_field_value);
        if (strcasecmp(p_field_name, "s") == 0)
        {
            if (strcasecmp(p_field_value, "Play") != 0)
            {
                sip_free((void **) &p_field_name);
                sip_free((void **) &p_field_value);
                return FR_SUCC;
            }
        }
        else if (strcasecmp(p_field_name, "c") == 0)
        {
            if (i_is_req == FR_YES)
            {
                sip_free((void **) &(p_st_sip_stmt->p_ui_media_dst_ip));
                p_st_sip_stmt->i_media_dst_ip_len = 0;
                if (__sdp_field_c(p_field_value, strlen(p_field_value), &(p_st_sip_stmt->p_ui_media_dst_ip), &(p_st_sip_stmt->i_media_dst_ip_len)) != FR_SUCC)
                    goto error;
            }
            else
            {
                sip_free((void **) &(p_st_sip_stmt->p_ui_media_src_ip));
                p_st_sip_stmt->i_media_src_ip_len = 0;
                if (__sdp_field_c(p_field_value, strlen(p_field_value), &(p_st_sip_stmt->p_ui_media_src_ip), &(p_st_sip_stmt->i_media_src_ip_len)) != FR_SUCC)
                    goto error;
            }
        }
        else if (strcasecmp(p_field_name, "m") == 0)
        {
            if (i_is_req == FR_YES)
            {
                sip_free((void **) &(p_st_sip_stmt->p_i_media_dst_port));
                p_st_sip_stmt->i_media_dst_port_len = 0;
                if (__sdp_field_m(p_field_value, strlen(p_field_value), &(p_st_sip_stmt->p_i_media_dst_port), &(p_st_sip_stmt->i_media_dst_port_len), &(p_st_sip_stmt->us_proto)) != FR_SUCC)
                    goto error;
            }
            else
            {
                sip_free((void **) &(p_st_sip_stmt->p_i_media_src_port));
                p_st_sip_stmt->i_media_src_port_len = 0;
                if (__sdp_field_m(p_field_value, strlen(p_field_value), &(p_st_sip_stmt->p_i_media_src_port), &(p_st_sip_stmt->i_media_src_port_len), &(p_st_sip_stmt->us_proto)) != FR_SUCC)
                    goto error;
            }
        }

        sip_free((void **) &p_field_name);
        sip_free((void **) &p_field_value);
        if ((ui_offset = p_line_end_pos - p_payload + strlen(APM_SIP_EOL)) >= (unsigned int) i_payload_len)
            break;
    }

    return FR_SUCC;
error:
    sip_free((void **) &p_field_name);
    sip_free((void **) &p_field_value);
    return FR_FAIL;
}
